package Model;

import java.awt.*;

public class EqualizerAnimations extends java.applet.Applet implements Runnable {

	 private int frameNumber = 0;
	 private int frameCount = -1;
	 private int millisecondsPerFrame = 100;
	 private int minimumSleepTime = 10;
	   
	 private long startTime;
	 private long oldElapsedTime;
	 private long elapsedTime;
	   
	 private Thread runner;
	   
	 private Image OSC;
	 private Graphics OSG;
	   
	 private final static int GO = 0, SUSPEND = 1, TERMINATE = 2;
	 private int status = SUSPEND;
	   
	 private int width = -1;
	 private int height = -1;

	
   public void drawFrame(Graphics g) {
      g.setColor(getBackground());
      g.fillRect(0,0,getWidth(),getHeight());
   }
   
   public int getFrameNumber() {
      return frameNumber;
   }
   

   public void setFrameNumber(int frameNumber) {
      if (frameNumber < 0)
         this.frameNumber = 0;
      else
         this.frameNumber = frameNumber;      
   }
   
   
   public int getWidth() {
       return size().width;
   }
   
   
   public int getHeight() {
       return size().height;
   }
   

   public long getElapsedTime() {
      return elapsedTime;
   }
   

   public void setFrameCount(int max) {
      if (max <= 0)
         this.frameCount = -1;
      else 
         frameCount = max;
   }
   

   public void setMillisecondsPerFrame(int time) {
      millisecondsPerFrame = time;
   }
   

   public void setMinimumSleepTime(int time) {
      if (time < 0)
         minimumSleepTime = 0;
      else
         minimumSleepTime = time;
   }

   synchronized public void start() {
      if (runner == null || !runner.isAlive()) {
         runner = new Thread(this);
         runner.start();
      }
      status = GO;
      startTime = -1;
      notify();
   }
   
   synchronized public void stop() {
      oldElapsedTime += (System.currentTimeMillis() - startTime);
      status = SUSPEND;
      notify();
   }
   
   public void destroy() {
      if (runner != null && runner.isAlive()) {
         synchronized(this) {
            status = TERMINATE;
            notify();
         }
      }
   }
   
   public void update(Graphics g) {
      paint(g);
   }
   
   synchronized public void paint(Graphics g) {
      if (width != size().width || height != size().height) {
         doSetup();
         if (OSC != null)
            drawFrame(OSG);
      }
      if (OSC == null)
         drawFrame(g);
      else  
         g.drawImage(OSC,0,0,this);
   }
   
   private void doSetup() {
      width = size().width;
      height = size().height;
      OSC = null;
      try {
         OSC = createImage(width,height);
         OSG = OSC.getGraphics();
      }
      catch (OutOfMemoryError e) {
         OSC = null;
         OSG = null;
      }
   }
   
   public void run() {
      long lastFrameTime = 0;
      while (true) {
         synchronized(this) {
            while (status == SUSPEND) {
               try {
                  wait();
               }
               catch (InterruptedException e) {
               }
            }
            if (status == TERMINATE) { 
               return;
            }
            if (width != size().width || height != size().height) 
               doSetup();
            if (startTime == -1) {
               startTime = System.currentTimeMillis();
               elapsedTime = oldElapsedTime;
            }
            else
               elapsedTime = oldElapsedTime + (System.currentTimeMillis() - startTime);
            if (frameCount >= 0 && frameNumber >= frameCount)
               frameNumber = 0;
            if (OSC != null)
               drawFrame(OSG);   
            frameNumber++;
         }
         long time = System.currentTimeMillis();
         long sleepTime = (lastFrameTime + millisecondsPerFrame) - time;
         if (sleepTime < minimumSleepTime)
            sleepTime = minimumSleepTime;
         repaint();  
         if (sleepTime <= 0)
            Thread.yield();
         else {
            try {
               synchronized(this) {
                 wait(sleepTime);
               }
            }
            catch (InterruptedException e) { }
         }
         lastFrameTime = System.currentTimeMillis();
      }
   }
}
